package com.example.act6.common.handler;


import com.example.act6.common.entities.CommonResult;
import com.example.act6.common.enums.ExceptionEnum;
import com.example.act6.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException;
import org.springframework.dao.*;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;


import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;

/**
 * @return {@link null}
 * @Author jrw
 * @Description 全局异常统一处理
 * @Date 2022/3/7 16:18
 * @Param 
 **/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(RuntimeException.class)
    public CommonResult exHandler(RuntimeException ex) {
        log.error(ExceptionEnum.RUNTIME_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.RUNTIME_EXCEPTION.getCode(), ExceptionEnum.RUNTIME_EXCEPTION.getMessage());
    }

    @ExceptionHandler(NullPointerException.class)
    public CommonResult exHandler(NullPointerException ex) {
        log.error(ExceptionEnum.NULLPOINTER_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.NULLPOINTER_EXCEPTION.getCode(), ExceptionEnum.NULLPOINTER_EXCEPTION.getMessage());
    }

    @ExceptionHandler(SQLException.class)
    public CommonResult exHandler(SQLException ex) {
        log.error(ExceptionEnum.SQL_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.SQL_EXCEPTION.getCode(), ExceptionEnum.SQL_EXCEPTION.getMessage());
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public CommonResult exHandler(HttpMessageNotReadableException ex) {
        log.error(ExceptionEnum.HTPP_MESSAGE_NOTREADABLE_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.HTPP_MESSAGE_NOTREADABLE_EXCEPTION.getCode(), ExceptionEnum.HTPP_MESSAGE_NOTREADABLE_EXCEPTION.getMessage());
    }

    @ExceptionHandler(DataAccessException.class)
    public CommonResult exHandler(DataAccessException ex) {
        log.error(ExceptionEnum.DATAACCESS_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.DATAACCESS_EXCEPTION.getCode(), ExceptionEnum.DATAACCESS_EXCEPTION.getMessage());
    }

    @ExceptionHandler(TypeMismatchDataAccessException.class)
    public CommonResult exHandler(TypeMismatchDataAccessException ex) {
        log.error(ExceptionEnum.TYPEMISMATCH_DATAACCESS_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.TYPEMISMATCH_DATAACCESS_EXCEPTION.getCode(), ExceptionEnum.TYPEMISMATCH_DATAACCESS_EXCEPTION.getMessage());
    }

    @ExceptionHandler(DeadlockLoserDataAccessException.class)
    public CommonResult exHandler(DeadlockLoserDataAccessException ex) {
        log.error(ExceptionEnum.DEADLOCKLOSER_DATAACCESS_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.DEADLOCKLOSER_DATAACCESS_EXCEPTION.getCode(), ExceptionEnum.DEADLOCKLOSER_DATAACCESS_EXCEPTION.getMessage());
    }

    @ExceptionHandler(DuplicateKeyException.class)
    public CommonResult exHandler(DuplicateKeyException ex) {
        log.error(ExceptionEnum.DUPLICATEKEY_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.DUPLICATEKEY_EXCEPTION.getCode(), ExceptionEnum.DUPLICATEKEY_EXCEPTION.getMessage());
    }

    @ExceptionHandler(DataAccessResourceFailureException.class)
    public CommonResult exHandler(DataAccessResourceFailureException ex) {
        log.error(ExceptionEnum.RESOURCE_FAILURE_DATAACCESS_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.RESOURCE_FAILURE_DATAACCESS_EXCEPTION.getCode(), ExceptionEnum.RESOURCE_FAILURE_DATAACCESS_EXCEPTION.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public CommonResult exHandler(MethodArgumentNotValidException ex) {
        log.error(ExceptionEnum.VALID_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        BindingResult result = ex.getBindingResult();
        String message = StringUtils.EMPTY;
        if (result.hasErrors()) {
            List<ObjectError> errors = result.getAllErrors();
            if (errors != null) {
                errors.forEach(p -> {
                    FieldError fieldError = (FieldError) p;
                    log.error("Data check failure : object{" + fieldError.getObjectName() + "},field{" + fieldError.getField() +
                            "},errorMessage{" + fieldError.getDefaultMessage() + "}");

                });
                if (errors.size() > 0) {
                    FieldError fieldError = (FieldError) errors.get(0);
                    message = fieldError.getDefaultMessage();
                }
            }
        }
        return CommonResult.error(ExceptionEnum.VALID_EXCEPTION.getCode(), message);
    }

    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public CommonResult exHandler(HttpMediaTypeNotSupportedException ex) {
        log.error(ExceptionEnum.HTTP_MEDIA_TYPE_NOT_SUPPORTED_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.HTTP_MEDIA_TYPE_NOT_SUPPORTED_EXCEPTION.getCode(), ExceptionEnum.HTTP_MEDIA_TYPE_NOT_SUPPORTED_EXCEPTION.getMessage());
    }

    @ExceptionHandler(NumberFormatException.class)
    public CommonResult exHandler(NumberFormatException ex) {
        log.error(ExceptionEnum.NUMBERFORMAT_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.NUMBERFORMAT_EXCEPTION.getCode(), ExceptionEnum.NUMBERFORMAT_EXCEPTION.getMessage());
    }

    @ExceptionHandler(BusinessException.class)
	public CommonResult exHandler(BusinessException ex) {
		StackTraceElement stackTraceElement = null;
		for (StackTraceElement item : ex.getStackTrace()) {
			if (item.getClassName().startsWith("com.plantmate.provider.commoditycenter") && !item.getClassName().equals(BusinessException.class.getName())) {
				stackTraceElement = item;
				break;
			}
		}
		if (stackTraceElement == null) {// 正常情况下不会执行到此处
			log.error(ExceptionEnum.BUSINESS_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
		} else {// 此处不用打印详细的异常堆栈信息
			log.error("OrderBusinessException, message={}, location={}", ex.getMessage(), stackTraceElement);
		}
        Integer errorCode = ex.getCode();
        if (errorCode == null) {
            errorCode = ExceptionEnum.BUSINESS_EXCEPTION.getCode();
        }
		return CommonResult.error(ExceptionEnum.BUSINESS_EXCEPTION.getCode(), ex.getMessage());
	}
    @ExceptionHandler(IllegalArgumentException.class)
    public CommonResult exHandler(IllegalArgumentException ex) {
        log.error(ExceptionEnum.VALID_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.VALID_EXCEPTION.getCode(), ex.getMessage());
    }

    @ExceptionHandler(SizeLimitExceededException.class)
    public CommonResult exHandler(SizeLimitExceededException ex) {
        log.error(ExceptionEnum.SIZE_LIMIT_EXCEEDED_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.SIZE_LIMIT_EXCEEDED_EXCEPTION.getCode(), ExceptionEnum.SIZE_LIMIT_EXCEEDED_EXCEPTION.getMessage());
    }

    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public CommonResult exHandler(MaxUploadSizeExceededException ex) {
        log.error(ExceptionEnum.SIZE_LIMIT_EXCEEDED_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.SIZE_LIMIT_EXCEEDED_EXCEPTION.getCode(), ExceptionEnum.SIZE_LIMIT_EXCEEDED_EXCEPTION.getMessage());
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public CommonResult exHandler(MethodArgumentTypeMismatchException ex) {
        log.error(ExceptionEnum.METHOD_ARGUMENT_TYPE_MISMATCH_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.METHOD_ARGUMENT_TYPE_MISMATCH_EXCEPTION.getCode(), ExceptionEnum.METHOD_ARGUMENT_TYPE_MISMATCH_EXCEPTION.getMessage());
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public CommonResult exHandler(MissingServletRequestParameterException ex) {
        log.error(ExceptionEnum.MISSING_SERVLET_REQUESR_PARAMETER_EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.MISSING_SERVLET_REQUESR_PARAMETER_EXCEPTION.getCode(), ExceptionEnum.MISSING_SERVLET_REQUESR_PARAMETER_EXCEPTION.getMessage());
    }

//    @ExceptionHandler(ConstraintViolationException.class)
//    public CommonResult exHandler(ConstraintViolationException ex) {
//        log.error(ExceptionEnum.CONSTRAINT_VIOLATION_EXCEPTION.getMessage() + "--", ex);
//        Iterator<ConstraintViolation<?>> iterator = ex.getConstraintViolations().iterator();
//        if (iterator.hasNext()) {
//            return CommonResult.error(ExceptionEnum.CONSTRAINT_VIOLATION_EXCEPTION.getCode(), iterator.next().getMessage());
//        }
//        return CommonResult.error(ExceptionEnum.CONSTRAINT_VIOLATION_EXCEPTION.getCode(), ExceptionEnum.CONSTRAINT_VIOLATION_EXCEPTION.getMessage());
//    }

    @ExceptionHandler(Exception.class)
    public CommonResult exHandler(Exception ex) {
        log.error(ExceptionEnum.EXCEPTION.getMessage() + ":{}", ex.getMessage(), ex);
        return CommonResult.error(ExceptionEnum.EXCEPTION.getCode(), ex.getMessage());
    }


}
